﻿using System;
using System.Collections.Generic;
using System.IO;
using FNN.CustomFunctions;
using FNN.Helpers;
using FNN.NetworkMasters;
using FNN.Networks;
using FNN.SourcePoints;
using FNN.Helpers.IO;
using FNN.Helpers.DataSource;
using FNN.Factories.SourcePoints;
using FNN.EventArguments;

namespace FinancialNeuronNetwork
{
    internal class Program
    {
        private static readonly FinancialNetworkMaster NetMaster = new FinancialNetworkMaster();
        private static FinancialNetwork _currentNetwork;
        
        private static void Main(string[] args)
        {
            var serializationHelper = new SerializationHelper();
            if (args.Length > 0)
            {
                if (args[0].ToLower().Contains("train"))
                {
                    var networkName = args[1];
                    var pathToData = args[2];
                    var param = Convert.ToInt32(args[4]);

                    var helper = new DataSourceHelper(
                                new CsvHelper(pathToData),
                                new DateSourcePointFactory()
                            );

                    NetMaster.DataSource = helper.GetDataSource();

                    _currentNetwork = (FinancialNetwork) serializationHelper.LoadBinary(networkName + ".fnn");
                    if (_currentNetwork == null)
                    {
                        Console.WriteLine("Ошибка! Файл поврежден или имел неверный формат!");
                        return;
                    }

                    NetMaster.TimeLimit = 0;
                    NetMaster.IterationsLimit = 0;
                    NetMaster.PopulationCount = 3;

                    if (args[3].ToLower().Contains("time"))
                    {
                        NetMaster.TimeLimit = param;
                    }
                    else if (args[3].ToLower().Contains("iterations"))
                    {
                        NetMaster.IterationsLimit = param;
                    }
                    else if (args[3].ToLower().Contains("profit"))
                    {
                        NetMaster.TargetResult = param;
                    }
                    else
                    {
                        Console.WriteLine("Некорректные аргументы!");
                    }

                    Console.WriteLine("Обучаем сеть...");
                    NetMaster.ResultsImprovedWithCount += NetMaster_ResultsImprovedWithCount;

                    var result = NetMaster.TrainMultiNetwork(_currentNetwork);
                    Console.WriteLine("Сеть обучена, записываем в файл...");

                    serializationHelper.WriteBinary(result, networkName + ".fnn");
                    Console.WriteLine("Готово!");
                }
                else if (args[0].ToLower().Contains("create"))
                {
                    var networkName = args[1];
                    var inputCount = Convert.ToInt32(args[2]);
                    var layersCount = Convert.ToInt32(args[3]);
                    var layerNeuronsCount = Convert.ToInt32(args[4]);
                    var outputNeuronsCount = Convert.ToInt32(args[5]);
                    var functionType = (FunctionTypes) Convert.ToInt32(args[6]);
                    var pathToData = args[7];

                    var helper = new DataSourceHelper(
                                new CsvHelper(pathToData),
                                new DateSourcePointFactory()
                            );

                    NetMaster.DataSource = helper.GetDataSource();

                    _currentNetwork = new FinancialNetwork(inputCount, layersCount, layerNeuronsCount,
                        new List<FunctionTypes> {functionType}, outputNeuronsCount);

                    _currentNetwork.NetworkName = networkName;

                    NetMaster.IterationsLimit = 0;
                    NetMaster.TimeLimit = 6;
                    NetMaster.PopulationCount = 10;

                    Console.WriteLine("Обучаем сеть...");
                    NetMaster.ResultsImprovedWithCount += NetMaster_ResultsImprovedWithCount;

                    var result = NetMaster.TrainMultiNetwork(_currentNetwork);
                    Console.WriteLine("Сеть обучена, записываем в файл...");

                    serializationHelper.WriteBinary(result, networkName + ".fnn");
                    Console.WriteLine("Готово!");
                }
                else if (args[0].ToLower().Contains("help"))
                {
                    if (!File.Exists("readme.txt")) return;
                    Console.Clear();
                    var helpFile = File.ReadAllLines("readme.txt");
                    foreach (var row in helpFile)
                    {
                        Console.WriteLine(row);
                    }
                }
                else
                {
                    Console.WriteLine("Некорректные аргументы!");
                }
            }
            else
            {
                Console.WriteLine("Вас приветствует мастер по созданию и обучению сети");
                Console.Write("Что бы Вы хотели сделать (create/open): ");
                var action = Console.ReadLine() ?? "";
                if (action.ToLower().Contains("open"))
                {
                    Console.Write("Название сети: ");
                    var networkName = Console.ReadLine();
                    Console.Write("Путь к данным: ");
                    var pathToData = Console.ReadLine();
                    Console.Write("Время обучения (в секундах): ");
                    var timeLimit = Convert.ToInt32(Console.ReadLine());
                    Console.Write("Количество итераций: ");
                    var iterationsLimit = Convert.ToInt32(Console.ReadLine());
                    Console.Write("Процент прибыли: ");
                    var profitPercent = Convert.ToInt32(Console.ReadLine());

                    var helper = new DataSourceHelper(
                                new CsvHelper(pathToData),
                                new DateSourcePointFactory()
                            );

                    NetMaster.DataSource = helper.GetDataSource();

                    NetMaster.TimeLimit = timeLimit;
                    NetMaster.IterationsLimit = iterationsLimit;
                    NetMaster.TargetResult = profitPercent;
                    NetMaster.PopulationCount = 10;

                    _currentNetwork = (FinancialNetwork) serializationHelper.LoadBinary(networkName + ".fnn");
                    if (_currentNetwork == null)
                    {
                        Console.WriteLine("Ошибка! Файл поврежден или имел неверный формат!");
                        return;
                    }
                    Console.WriteLine("Обучаем сеть...");
                    NetMaster.ResultsImprovedWithCount += NetMaster_ResultsImprovedWithCount;

                    var result = NetMaster.TrainMultiNetwork(_currentNetwork);
                    Console.WriteLine("Сеть обучена, записываем в файл...");

                    serializationHelper.WriteBinary(result, networkName + ".fnn");
                    Console.WriteLine("Готово!");
                }
                else
                {
                    Console.Write("Название сети: ");
                    var networkName = Console.ReadLine();
                    Console.Write("Количество входов: ");
                    var inputCount = Convert.ToInt32(Console.ReadLine());
                    Console.Write("Количество слоев: ");
                    var layerCount = Convert.ToInt32(Console.ReadLine());
                    Console.Write("Количество нейронов в слое: ");
                    var layerNeuronsCount = Convert.ToInt32(Console.ReadLine());
                    Console.Write("Количество выходных нейронов: ");
                    var outputNeuronsCount = Convert.ToInt32(Console.ReadLine());
                    Console.Write("Тип активационной функции: ");
                    var functionType = (FunctionTypes) Convert.ToInt32(Console.ReadLine());
                    Console.Write("Путь к данным: ");
                    var pathToData = Console.ReadLine();

                    var helper = new DataSourceHelper(
                                new CsvHelper(pathToData),
                                new DateSourcePointFactory()
                            );

                    NetMaster.DataSource = helper.GetDataSource();

                    _currentNetwork = new FinancialNetwork(inputCount, layerCount, layerNeuronsCount,
                        new List<FunctionTypes> {functionType}, outputNeuronsCount);

                    _currentNetwork.NetworkName = networkName;

                    NetMaster.IterationsLimit = 0;
                    NetMaster.TimeLimit = 6;
                    NetMaster.PopulationCount = 10;
                    Console.WriteLine("Обучаем сеть...");
                    NetMaster.ResultsImprovedWithCount += NetMaster_ResultsImprovedWithCount;

                    var result = NetMaster.TrainMultiNetwork(_currentNetwork);
                    Console.WriteLine("Сеть обучена, записываем в файл...");

                    serializationHelper.WriteBinary(result, networkName + ".fnn");
                    Console.WriteLine("Готово!");
                }
            }
            Console.ReadKey();
        }

        private static void NetMaster_ResultsImprovedWithCount(object sender, ResultChangedExtendedEventArgs e)
        {
            Console.WriteLine("Результат сети улучшился. Текущий результат: " + e.IterationResult);
            Console.WriteLine("Текущее количество операций: " + e.OperationsCount);
        }
    }
}